﻿using System.Data.SqlClient;
using System.Data.SQLite;
using System.Linq;
using Crawler.DataServices.Persistence.UnitOfWork;
using Crawler.Domain.DataEntities.Extracted;
using Crawler.DomainServices.DataServices;
using NHibernate;
using StructureMap;

namespace Crawler.DataServices.Repositories
{
	internal class MoviesRepository : IMoviesRepository
	{
		public void Save(MovieFile data)
		{
			try
			{
				using (var uoc = ObjectFactory.GetInstance<IUnitOfWork>())
				{
					uoc.Session.SaveOrUpdate(data);
					uoc.Commit();
				}
			}
			catch (ADOException ex)
			{
				if (RemoveDuplicatedMoviesFilesHandled(data as MovieFile, ex))
					return;
				if (RemoveDuplicatedMoviesHandled(data as MovieFile, ex))
					return;
				throw;
			}
		}

		public Movie GetMovieByTitle(string title, int year)
		{
			using (var uoc = ObjectFactory.GetInstance<IUnitOfWork>())
			{
				return uoc.Session.QueryOver<Movie>().Where(x => x.Title == title && x.Year == year).List().FirstOrDefault();
			}
		}

		public MovieFile GetMovieFileByUrl(string url)
		{
			using (var uoc = ObjectFactory.GetInstance<IUnitOfWork>())
			{
				return uoc.Session.QueryOver<MovieFile>().Where(x => x.FromUrl == url).List().SingleOrDefault();
			}
		}

		public int CountFileByUrl(string url)
		{
			using (var uoc = ObjectFactory.GetInstance<IUnitOfWork>())
			{
				return uoc.Session.QueryOver<MovieFile>().Where(x => x.FromUrl == url).RowCount();
			}
		}

		private bool RemoveDuplicatedMoviesHandled(MovieFile movieFile, ADOException ex)
		{
			if (movieFile == null) return false;
			var sqlEx = ex.InnerException as SqlException;
			var sqliteEx = ex.InnerException as SQLiteException;
			if ((sqlEx != null && sqlEx.Number == 2627) || (sqliteEx != null && sqliteEx.ErrorCode == 19)) //unique violation
			{
				string title = movieFile.Movie.Title;
				int year = movieFile.Movie.Year;
				using (var uoc = ObjectFactory.GetInstance<IUnitOfWork>())
				{
					Movie movie = uoc.Session.QueryOver<Movie>().Where(x => x.Title == title && x.Year == year).SingleOrDefault();
					if (movie != null)
					{
						uoc.Session.Evict(movieFile.Movie);
						movieFile.Movie = movie;
					}
					

					uoc.Session.SaveOrUpdate(movieFile);
					uoc.Commit();
				}
				return true;
			}
			return false;
		}

		private bool RemoveDuplicatedMoviesFilesHandled(MovieFile movieFile, ADOException ex)
		{
			if (movieFile == null) return false;
			var sqlEx = ex.InnerException as SqlException;
			var sqliteEx = ex.InnerException as SQLiteException;
			if ((sqlEx != null && sqlEx.Number == 2627) || (sqliteEx != null && sqliteEx.ErrorCode == 19)) //unique violation
			{
				using (var uoc = ObjectFactory.GetInstance<IUnitOfWork>())
					if (uoc.Session.QueryOver<MovieFile>().Where(x => x.FromUrl == movieFile.FromUrl).RowCount() > 0)
						return true;
			}
			return false;
		}
	}
}